<?php

namespace app\api\controller\v3;
use app\Request;
use app\services\other\UploadService;
use think\facade\Db;
use app\services\pay\SmfpayServices;

/**
 * 微信服务商V3
 */
class Wxpaymch
{
    // 错误信息
    private $error = '';
    // 商户mchid
    private $mch_id;
    // 商户API v3密钥(微信服务商-账户中心-API安全 api v3密钥 https://pay.weixin.qq.com/index.php/core/cert/api_cert)
    private $mch_api_key;
    // 证书编号 (apiclient_cert.pem证书解析后获得)
    private $serial_no ;
    // 私钥 apiclient_key.pem(微信服务商-账户中心-API安全 自行下载 https://pay.weixin.qq.com/index.php/core/cert/api_cert)
//    private $mch_private_key = __DIR__ . DIRECTORY_SEPARATOR . 'cert' . DIRECTORY_SEPARATOR . 'apiclient_key.pem';
    private $mch_private_key;
    // 支付平台公钥(接口获取)
//    private $public_key_path = __DIR__ . DIRECTORY_SEPARATOR . 'cert_ficates_v3.pem';
    private $public_key_path;

    //初始化
    public function __construct()
    {
        $this->mch_id = sys_config('pay_weixin_mchid_v3');
        $this->mch_api_key = sys_config('pay_weixin_key_v3');
        $this->serial_no = sys_config('pay_weixin_serial_no');
        $this->mch_private_key = public_path() . getPemPath(sys_config('pay_weixin_client_cert_v3'));
        //平台证书
        $this->public_key_path = public_path()."/uploads/wx/pt.pem";
    }
    /*
     * 微信特约商户进件接口
     * //$json = "{\"id\":\"\",\"business_code\":\"\",\"subject_info\":{\"identity_info\":{\"id_doc_type\":\"IDENTIFICATION_TYPE_IDCARD\",\"id_card_info\":{\"id_card_copy\":\"V1_yNKOyDQ1-DtJ3gRItSJScR5zVdjRHmPrPLPgFhabF_R0YyNuf98NIZTJyBZkFvkxSMxnM2Uhd_VuS64DTSgPiALJOzY9eQhmv6giwKWUAjk\",\"id_card_national\":\"V1_6C2nXoLKqrxYbMUFaWDVcR5zVdjRHmNDUTnuq31j7uYlAjQtTJiCIY_jyBZkFvkxg1I2cmVTOt31hCBs6bDiwALJOzY9eQhmv6giwKWUAjk\",\"id_card_name\":\"wer\",\"id_card_number\":\"234234\",\"card_period_begin\":\"2026-06-06\",\"card_period_end\":\"2026-06-06\"},\"id_doc_info\":{\"id_doc_copy\":\"\",\"id_doc_copy_back\":\"\",\"id_doc_name\":\"\",\"id_doc_number\":\"\",\"doc_period_begin\":\"\",\"doc_period_end\":\"\"},\"owner\":true},\"subject_type\":\"SUBJECT_TYPE_INDIVIDUAL\",\"ubo_info_list\":[],\"business_license_info\":{\"license_copy\":\"V1_Ezg82z_Lxa0k_ve6apRI2x5zVdjRHmNNCWA5EsxiwHr7IWPCx3bqIen6yRZkFvkxu7xAq3dzZ96dEWy7toeIwgLJOzY9eQhmv6giwKWUAjk\",\"license_number\":\"32452wre\",\"merchant_name\":\"23\",\"legal_person\":\"wer\"}},\"business_info\":{\"merchant_shortname\":\"erw\",\"service_phone\":\"18874824331\",\"sales_info\":{\"sales_scenes_type\":[],\"mini_program_info\":{},\"app_info\":{}}},\"bank_account_info\":{\"bank_account_type\":\"BANK_ACCOUNT_TYPE_CORPORATE\",\"account_name\":\"werw\",\"account_bank\":\"\u4ea4\u901a\u94f6\u884c\",\"bank_address_code\":\"110100\",\"account_number\":\"451278456589541254\"},\"contact_info\":{\"contact_type\":\"LEGAL\",\"contact_name\":\"32\",\"contact_id_doc_type\":\"\",\"contact_id_number\":\"\",\"contact_id_doc_copy\":\"\",\"contact_id_doc_copy_back\":\"\",\"contact_period_begin\":\"\",\"contact_period_end\":\"\",\"business_authorization_letter\":\"\",\"openid\":\"\",\"mobile_phone\":\"18874824331\",\"contact_email\":\"1512917357@qq.com\"}}";
     * //$data = json_decode($json,true);
     */
    public function subApplyment()
    {
        $json = file_get_contents('php://input');
        if(!$json)return app('json')->fail('缺少参数');
        $data = json_decode($json,true);//json转数组
        if($data['applyment_type']=='smf'){
            $smf = new SmfpayServices();
            $smfdata = $smf->smf_subApplyment($data);
            if($smfdata==1) return app('json')->success("提交成功");
            exit;
        }
        $arr = $data;
//        p($data);exit;
        $id = $data['id'];//约你游app传过来的会员id
        $business_code = $data['business_code'];
        $check = Db::name('wx_applyment')->where('uid',$id)->where('applyment_state','<>',"已驳回")->find();
        if($check)return app('json')->fail('已提交资料申请，无需重复提交！');
        if(!$data['business_code']){
            $business_code = $this->getBusinessCode();
        }
        $contact_info = $data['contact_info'];//【超级管理员信息】
        $z1 = json_encode($contact_info);
        $subject_info = $data['subject_info'];//【主体资料】
        $z2 = json_encode($subject_info);
        $business_info = $data['business_info'];//【经营资料】
        $z3 = json_encode($business_info);
        $bank_account_info = $data['bank_account_info'];//【结算银行账户】
        $z4 = json_encode($bank_account_info);
//        $settlement_info = (array)$data->settlement_info;
//        $addition_info = (array)$data->addition_info;
        // 参数准备
        $data = [
            //业务申请编号
            'business_code'     => $business_code,
            //超级管理员信息
            'contact_info'      => [
                'contact_type'      => $contact_info['contact_type'],
                'contact_name'      => $this->getEncrypt($contact_info['contact_name']),//超级管理员姓名
//                'contact_id_number' => $this->getEncrypt($contact_info['contact_id_number']),//超级管理员身份证件号码
                'mobile_phone'      => $this->getEncrypt($contact_info['mobile_phone']),//联系手机
                'contact_email'     => $this->getEncrypt($contact_info['contact_email']),//联系邮箱
                'name'=>$this->getEncrypt($contact_info['contact_name']),//【联系人姓名】

            ],
            //主体资料
            'subject_info'      => [
                //主体类型SUBJECT_TYPE_INDIVIDUAL（个体户）SUBJECT_TYPE_ENTERPRISE（企业）SUBJECT_TYPE_INSTITUTIONS（党政、机关及事业单位）SUBJECT_TYPE_OTHERS（其他组织）
                'subject_type'  => $subject_info['subject_type'],
                //【营业执照】主体为个体户/企业，必填
                'business_license_info'=>[
                    'license_copy'=>$subject_info['business_license_info']['license_copy'],//【营业执照照片】
                    'license_number'=>$subject_info['business_license_info']['license_number'],//【注册号/统一社会信用代码】
                    'merchant_name'=>$subject_info['business_license_info']['merchant_name'],//【商户名称】
                    'legal_person'=>$subject_info['business_license_info']['legal_person'],//【个体户经营者/法人姓名】
                ],
                //经营者/法人身份证件
                'identity_info' => [
                    'id_doc_type'  => $subject_info['identity_info']['id_doc_type'],//证件类型
                    'owner'        => true,//经营者/法人是否为受益人
                    //身份证信息
                    'id_card_info' => [
                        'id_card_copy'      =>$subject_info['identity_info']['id_card_info']['id_card_copy'],//【身份证人像面照片】
                        'id_card_national'  => $subject_info['identity_info']['id_card_info']['id_card_national'],//【身份证国徽面照片】
                        'id_card_name'      => $this->getEncrypt($subject_info['identity_info']['id_card_info']['id_card_name']),//【身份证姓名】
                        'id_card_number'    => $this->getEncrypt($subject_info['identity_info']['id_card_info']['id_card_number']),//【身份证号码】
                        'card_period_begin' => $subject_info['identity_info']['id_card_info']['card_period_begin'],//【身份证有效期开始时间】
                        'card_period_end'   => $subject_info['identity_info']['id_card_info']['card_period_end'],//【身份证有效期结束时间】
                        'id_card_address'=>$this->getEncrypt($subject_info['identity_info']['id_card_info']['id_card_address']),//【身份证居住地址】
                    ],
                ],
            ],
            //经营资料
            'business_info'     => [
                'merchant_shortname' => $business_info['merchant_shortname'],//【商户简称】
                'service_phone'      => $business_info['service_phone'],//【客服电话】
                'sales_info'         => [
                    'sales_scenes_type' => ['SALES_SCENES_MINI_PROGRAM','SALES_SCENES_APP'],//小程序和APP
                    //经营场景类型【小程序场景】
                    'mini_program_info'=>[
                    "mini_program_appid" => "wx35545e6faed1ad9b",
//                    "mini_program_pics" => [//【小程序截图】
//                        "example_mini_program_pics"
//                    ],
                 ],
                    //经营场景类型【App场景】
                    'app_info'=>[
                        "app_appid" => "wxb8d9a8cbe71c948f",
                    "app_pics" => [//【App截图】
                        "V1_3dKFc8kCRTkvyZ4QvsWEfx5zVdjRHmNUd1EEJfECh9ZwMXy_JczPIanJ0WBkFvkxXG7PTIObG9iodZ1gyuhynALJOzY9eQhmv6giwKWUAjk",
                        "V1_Rb8OHKhGnnGvYaJtfhLfWB5zVdjRHmM1VOAraqcEloRSzWhRX5-oIfKS0mBkFvkxwxGKspR_7i_JXGx6qwltoALJOzY9eQhmv6giwKWUAjk",
                        "V1_Zc3SZMFp4G504wD-T-F2eR5zVdjRHmMDRHDNy2L5WXWfibJ0kPskIfSjzWBkFvkxAAfWiaK9LauX9wprb4y7QALJOzY9eQhmv6giwKWUAjk",
                        "V1_Jj9QJ4BIxFVqdI8iFDHMVh5zVdjRHmNuuLBEyrARfa8djCN5H81vIb_kx2BkFvkxKDcUDQ5rc8VmQdGbpnQuwQLJOzY9eQhmv6giwKWUAjk",
                        "V1_PefV-dXk6y-5L9OlSTc19B5zVdjRHmOLuGOuslH--QsMiC8zhGDrIeuauHxuFvkxNgAqUN83osL6mpw_4TvaNwLJOzY9eQhmv6giwKWUAjk",
                    ],
                    ],
               ],
            ],
            //结算规则
            'settlement_info'   => [
                'settlement_id'      => "716",
                'qualification_type' => "居民生活服务",
//                'activities_id'      => $params['activities_id'],
//                'activities_rate'    => $params['activities_rate'],
            ],
            //结算银行账户
            'bank_account_info' => [
                'bank_account_type' => $bank_account_info['bank_account_type'],
                'account_name'      => $this->getEncrypt($bank_account_info['account_name']),
                'account_bank'      => $bank_account_info['account_bank'],
                'bank_address_code' => $bank_account_info['bank_address_code'],
//                'bank_name'         => $bank_account_info['bank_name'],
                'account_number'    => $this->getEncrypt($bank_account_info['account_number']),
            ],
            //补充材料
//            'addition_info'=>[
//                'legal_person_commitment'=>$params['legal_person_commitment'],
//                'business_addition_pics'=>$params['business_addition_pics'],
//            ],
        ];
        $url = 'https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/';

        // 获取支付平台证书编码(也可以用接口中返回的serial_no  来源：https://api.mch.weixin.qq.com/v3/certificates)
        $serial_no = $this->parseSerialNo($this->getCertFicates());

        $bodyData  = json_encode($data);

        // 获取认证信息
        $authorization = $this->getAuthorization($url, 'POST', $bodyData);

        $header = [
            'Content-Type:application/json',
            'Accept:application/json',
            'User-Agent:*/*',

            'Authorization:' . $authorization,
            'Wechatpay-Serial:' . $serial_no
        ];
        $json   = $this->getCurl('POST', $url, $bodyData, $header);
        $data2   = json_decode($json, true);
        if (isset($data2['code']) && isset($data2['message'])) {
            return app('json')->fail($data2['message']);

        }
        if (empty($applyment_id = $data2['applyment_id'])) {
            return app('json')->fail('[subApplyment]返回错误');

        }
        //插入自己数据库数据
        $list = [
            'business_code'=>$business_code,
            'contact_info'=>$z1,
            'subject_info'=>$z2,
            'business_info'=>$z3,
            'bank_account_info'=>$z4,
            'add_time'=>time(),
            'applyment_id'=>$applyment_id,
            'applyment_state'=>'已提交',
            'name'=>$arr['shopName'],
            'shopAddress'=>$arr['shopAddress'],
            'longitude'=>$arr['longitude'],
            'latitude'=>$arr['latitude'],
            'trade_stardate'=>$arr['trade_stardate'],
            'trade_enddate'=>$arr['trade_enddate'],
        ];
        $check_applyment =  Db::name('wx_applyment')->where('uid',$id)->where('applyment_state',"已驳回")->find();//如果是已驳回的状态重新提交
        if($check_applyment){
            Db::name('wx_applyment')->where('uid',$id)->update($list);//驳回重新提交
        }else{
            $list['uid'] = $id;
            $ynydzId = Db::name('wx_applyment')->insertGetId($list);//第一次提交成功获取店铺id
            $shopName = $arr['shopName'];
            $shopAddress = $arr['shopAddress'];
            $headImg = "https://ynytest-1300951025.cos.ap-chengdu.myqcloud.com/ynymanage/20240510/78d35ddc1420d14afc1987f1654a0b0a762f.png";
            $longitude = $arr['longitude'];
            $latitude = $arr['latitude'];
            $trade_stardate = $arr['trade_stardate'];
            $trade_enddate = $arr['trade_enddate'];
            $MerchantMemberId = $id;//会员id
            $yny_Data = [
                'shopName'=>$shopName,
                'shopAddress'=>$shopAddress,
                'headImg'=>$headImg,
                'longitude'=>$longitude,
                'latitude'=>$latitude,
                'ynydzId'=>$ynydzId,
                'trade_stardate'=>$trade_stardate,
                'trade_enddate'=>$trade_enddate,
                'MerchantMemberId'=>$MerchantMemberId,
            ];
            $this->ApplyTourShop($yny_Data);

        }
        return app('json')->success("提交成功");
    }

    /*
     * 调约你游接口申请店铺
     * */
    public function ApplyTourShop($yny_Data){
//        $yny_Data = [
//            'shopName'=>"强盛",
//            'shopAddress'=>"地址信息",
//            'headImg'=>"",
//            'longitude'=>'115.2',
//            'latitude'=>'95.3',
//            'ynydzId'=>2,
//            'trade_stardate'=>"08:00",
//            'trade_enddate'=>"22:00",
//            'MerchantMemberId'=>88929766,
//        ];
        $url = "https://apiv2.ta.klch.cn//api/NewActivity/ApplyTourShop";
        $headers = [ 'Content-Type: application/json; charset=utf-8'];
        $arr = http_post_json($url,$yny_Data,$headers);
        if($arr['status']==1){
            return 1;
        }
        return true;
    }

    //查询微信特约商户审核状态
    public function slect_bc_applyment(Request $request){
        $data =$request->getMore([
            ['id',''],
        ]);
        if(!$data['id'])throw new \Exception("未能处理正确请求");
        $wx_applyment = 0;//0未提交1已提交（审核中）2已驳回 3待签约 4已完成
        $wx_applyment_list = Db::name('wx_applyment')->where(['uid'=>$data['id']])->find();
        if($wx_applyment_list){
            $wx = new Wxpaymch();
            $check = $wx->queryApplyment2($wx_applyment_list['applyment_id']);//申请单号查询申请状态
            $audit_detail = "";//驳回原因
            $sign_url = "";//签约链接
            if($check['applyment_state']){
                switch ($check['applyment_state']) {
                    case "APPLYMENT_STATE_EDITTING":
                        $wx_applyment = "编辑中";
                        break;
                    case "APPLYMENT_STATE_AUDITING":
                        $wx_applyment = "审核中";
                        $sign_url = $check['sign_url'];
                        break;
                    case "APPLYMENT_STATE_REJECTED":
                        foreach($check['audit_detail'] as $k=>$v){
                            $audit_detail =$audit_detail."驳回原因"."[".$k."]".$v['reject_reason'];
                        }
                        $wx_applyment = "已驳回";
                        break;
                    case "APPLYMENT_STATE_TO_BE_CONFIRMED":
                        $wx_applyment = "待账户验证";
                        $sign_url = $check['sign_url'];
                        break;
                    case "APPLYMENT_STATE_TO_BE_SIGNED":
                        $wx_applyment = "待签约";
                        $sign_url = $check['sign_url'];
                        break;
                    case "APPLYMENT_STATE_SIGNING":
                        $wx_applyment = "开通权限中";
                        break;
                    case "APPLYMENT_STATE_FINISHED":
                        $wx_applyment = "已完成";
                        break;
                    case "APPLYMENT_STATE_CANCELED":
                        $wx_applyment = "已作废";
                        $wx_applyment = 0;
                        break;
                    default:
                        // 如果没有匹配的值
                }
            }
            $update = Db::name('wx_applyment')->where('id',$wx_applyment_list['id'])->update(['audit_detail'=>$audit_detail,'applyment_state'=>$wx_applyment]);
            if(isset($check['sub_mchid'])){
                Db::name('wx_applyment')->where('id',$wx_applyment_list['id'])->update(['mchid'=>$check['sub_mchid']]);
            }
            $list['wx_applyment'] = $wx_applyment;
            $list['audit_detail'] = $audit_detail;
            $list['sign_url'] = $sign_url;
        }else{
            $wx_applyment = 0;//0未提交1已提交（审核中）2已驳回 3待签约 4已完成
            $list['wx_applyment'] = $wx_applyment;
            $list['audit_detail'] = "";
            $list['sign_url'] = "";
        }
        return app('json')->success($list);

    }

    /*
     * 商户开户意愿确认提交
     * */
    public function yy_applyment(Request $request){
        $data =$request->getMore([
            ['id',''],
        ]);
        $wx_applyment_list = Db::name('wx_applyment')->where(['uid'=>$data['id']])->find();
        $business_code = $wx_applyment_list['business_code'];
        $contact_info = json_decode($wx_applyment_list['contact_info'],true);
        $subject_info = json_decode($wx_applyment_list['subject_info'],true);

        // 参数准备
        $data = [
            //业务申请编号
            'business_code'     => $business_code,
            //超级管理员信息
            'contact_info'      => [
                'contact_type'      => $contact_info['contact_type'],
                'contact_name'      => $this->getEncrypt($contact_info['contact_name']),//超级管理员姓名
                'name'=>$this->getEncrypt($contact_info['contact_name']),//【联系人姓名】
                'id_card_number' => $this->getEncrypt($contact_info['contact_id_number']),//超级管理员身份证件号码
                'mobile'      => $this->getEncrypt($contact_info['mobile_phone']),//联系手机
            ],
            //主体资料
            'subject_info'      => [
                //主体类型SUBJECT_TYPE_INDIVIDUAL（个体户）SUBJECT_TYPE_ENTERPRISE（企业）SUBJECT_TYPE_INSTITUTIONS（党政、机关及事业单位）SUBJECT_TYPE_OTHERS（其他组织）
                'subject_type'  => $subject_info['subject_type'],
                //【营业执照】主体为个体户/企业，必填
                'business_licence_info'=>[
                    'licence_copy'=>$subject_info['business_license_info']['license_copy'],//【营业执照照片】
                    'licence_number'=>$subject_info['business_license_info']['license_number'],//【注册号/统一社会信用代码】
                    'merchant_name'=>$subject_info['business_license_info']['merchant_name'],//【商户名称】
                    'legal_person'=>$subject_info['business_license_info']['legal_person'],//【个体户经营者/法人姓名】
                    'company_address'=>"未填写",//【注册地址】
                    'licence_valid_date'=>"",//【营业执照有效日期】[\\\"2017-10-28\\\",\\\"2037-10-28\\\"]
                ],
            ],
            //经营者/法人身份证件
            'identification_info' => [
                'identification_type'  => $subject_info['identity_info']['id_doc_type'],//证件类型
                'identification_front_copy'      =>$subject_info['identity_info']['id_card_info']['id_card_copy'],//【身份证人像面照片】
                'identification_back_copy'  => $subject_info['identity_info']['id_card_info']['id_card_national'],//【身份证国徽面照片】
                'identification_name'      => $this->getEncrypt($subject_info['identity_info']['id_card_info']['id_card_name']),//【身份证姓名】
                'identification_number'    => $this->getEncrypt($subject_info['identity_info']['id_card_info']['id_card_number']),//【身份证号码】
                'identification_valid_date' => [$subject_info['identity_info']['id_card_info']['card_period_begin'],$subject_info['identity_info']['id_card_info']['card_period_end']],//【身份证有效期开始时间】
                'identification_address'=>$this->getEncrypt($subject_info['identity_info']['id_card_info']['id_card_address']),//【身份证居住地址】
                'owner'        => true,//经营者/法人是否为受益人
            ],
        ];
        $url = 'https://api.mch.weixin.qq.com/v3/apply4subject/applyment/';

        // 获取支付平台证书编码(也可以用接口中返回的serial_no  来源：https://api.mch.weixin.qq.com/v3/certificates)
        $serial_no = $this->parseSerialNo($this->getCertFicates());

        $bodyData  = json_encode($data);

        // 获取认证信息
        $authorization = $this->getAuthorization($url, 'POST', $bodyData);

        $header = [
            'Content-Type:application/json',
            'Accept:application/json',
            'User-Agent:*/*',

            'Authorization:' . $authorization,
            'Wechatpay-Serial:' . $serial_no
        ];
        $json   = $this->getCurl('POST', $url, $bodyData, $header);
        $data   = json_decode($json, true);

        if (isset($data['code']) && isset($data['message'])) {
            return app('json')->fail($data['message']);
        }
        if (empty($applyment_id = $data['applyment_id'])) {
            return app('json')->fail('[subApplyment]返回错误');

        }

    }

    /**
     * 进件查询
     */
    public function queryApplyment($business_code)
    {
        $url = 'https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/business_code/' . $business_code;

        // 获取认证信息
        $authorization = $this->getAuthorization($url);
        $header        = [
            'Content-Type:application/json',
            'Accept:application/json',
            'User-Agent:*/*',

            'Authorization:' . $authorization
        ];
        $json = $this->getCurl('GET', $url, '', $header);

        $data = json_decode($json, true);

        if (isset($data['code']) && isset($data['message'])) {
            $this->error = '[queryApplyment]请求错误 code：' . $data['code'] . ' msg：' . $data['message'];
            return false;
        }
        return $data;
    }


    /**
     * 进件查询申请单号查询申请状态
     */
    public function queryApplyment2($applyment_id)
    {
        $url = 'https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/applyment_id/' . $applyment_id;

        // 获取认证信息
        $authorization = $this->getAuthorization($url);
        $header        = [
            'Content-Type:application/json',
            'Accept:application/json',
            'User-Agent:*/*',

            'Authorization:' . $authorization
        ];
        $json = $this->getCurl('GET', $url, '', $header);

        $data = json_decode($json, true);

        if (isset($data['code']) && isset($data['message'])) {
            $this->error = '[queryApplyment]请求错误 code：' . $data['code'] . ' msg：' . $data['message'];
            return false;
        }
        return $data;
    }


    /**
     * 上传文件
     */
    public function mediaUpload(Request $request)
    {
        $file = $request->postMore([
            ['filename', 'file'],
        ]);
        $fileHandle = app()->request->file($file['filename']);//上传图片至本地
        if (!$fileHandle) {
            $this->error = '上传的文件不存在';
        }
        //上传到腾讯云
        $data2 = input('ifa','0');
        $upload = UploadService::init(null,$data2);
        $info = $upload->to('car')->validate()->setAuthThumb(false)->move($file['filename']);
        if ($info === false) {
            return app('json')->fail($upload->getError());
        }
        $res = $upload->getUploadInfo();
        //上传到腾讯云
        $filepath = $fileHandle->getRealPath();//图片本地路径
        // 上传图片
        $filename = $fileHandle->getOriginalName();
        if (!file_exists($filepath)) {
            $this->error = '[mediaUpload]文件找不到';
        }
        $url       = 'https://api.mch.weixin.qq.com/v3/merchant/media/upload';
        $fi        = new \finfo(FILEINFO_MIME_TYPE);
        $mime_type = $fi->file($filepath);
        $meta      = [
            'filename' => $filename,
            'sha256'   => hash_file('sha256', $filepath)
        ];

        // 获取认证信息
        $authorization = $this->getAuthorization($url, 'POST', json_encode($meta));
        $boundary      = uniqid();
        $header        = [
            'Accept:application/json',
            'User-Agent:*/*',

            'Content-Type:multipart/form-data;boundary=' . $boundary,
            'Authorization:' . $authorization
        ];

        // 组合参数
        $boundaryStr = "--{$boundary}\r\n";
        $out         = $boundaryStr;
        $out         .= 'Content-Disposition: form-data; name="meta"' . "\r\n";
        $out         .= 'Content-Type: application/json' . "\r\n";
        $out         .= "\r\n";
        $out         .= json_encode($meta) . "\r\n";
        $out         .= $boundaryStr;
        $out         .= 'Content-Disposition: form-data; name="file"; filename="' . $filename . '"' . "\r\n";
        $out         .= 'Content-Type: ' . $mime_type . ';' . "\r\n";
        $out         .= "\r\n";
        $out         .= file_get_contents($filepath) . "\r\n";
        $out         .= "--{$boundary}--\r\n";
        $json        = $this->getCurl('POST', $url, $out, $header);
        $data        = json_decode($json, true);

        if (isset($data['code']) && isset($data['message'])) {
            $this->error = '[mediaUpload]请求错误 code：' . $data['code'] . ' msg：' . $data['message'];
            $this->getError();
            return false;
        }
        if (empty($media_id = $data['media_id'])) {
            $this->error = '[mediaUpload]返回错误';
            $this->getError();
            return false;
        }
        //记录
        $list = ['img'=>$res['dir'],'media_id'=>$media_id,'add_time'=>time()];
        Db::name('wx_img_log')->insert($list);
        $data['img'] = $res['dir'];
        return app('json')->success($data);
    }

    /**
     * 获取微信支付平台证书
     */
    public function certFicates()
    {
        $url = 'https://api.mch.weixin.qq.com/v3/certificates';

        // 获取认证信息
        $authorization = $this->getAuthorization($url);
        $header        = [
            'Content-Type:application/json',
            'Accept:application/json',
            'User-Agent:*/*',

            'Authorization:' . $authorization
        ];

        $json = $this->getCurl('GET', $url, '', $header);
        $data = json_decode($json, true);
        if (isset($data['code']) && isset($data['message'])) {
            $this->error = '[certFicates]请求错误 code：' . $data['code'] . ' msg：' . $data['message'];
            return false;
        }
        if (empty($cfdata = $data['data'][0])) {
            $this->error = '[certFicates]返回错误';
            return false;
        }
        return $cfdata;
    }

    /**
     * 获取认证信息
     * @param string $url
     * @param string $http_method
     * @param string $body
     * @return string
     * @throws Exception
     */
    private function getAuthorization($url, $http_method = 'GET', $body = '')
    {
        if (!in_array('sha256WithRSAEncryption', \openssl_get_md_methods(true))) {
            throw new \Exception("当前PHP环境不支持SHA256withRSA");
        }
        //私钥地址
        $mch_private_key = $this->mch_private_key;
        //商户号
        $merchant_id = $this->mch_id;
        //当前时间戳
        $timestamp = time();
        //随机字符串
        $nonce = $this->getNonceStr();
        //证书编号
        $serial_no = $this->serial_no;

        $url_parts     = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $message       = $http_method . "\n" .
            $canonical_url . "\n" .
            $timestamp . "\n" .
            $nonce . "\n" .
            $body . "\n";

        openssl_sign($message, $raw_sign, \openssl_get_privatekey(\file_get_contents($mch_private_key)), 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);

        $schema = 'WECHATPAY2-SHA256-RSA2048';
        $token  = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $merchant_id, $nonce, $timestamp, $serial_no, $sign);
        return $schema . ' ' . $token;
    }

    /**
     * 敏感字符加密
     * @param $str
     * @return string
     * @throws Exception
     */
    private function getEncrypt($str)
    {
        static $content;
        if (empty($content)) {
            $content = $this->getCertFicates();
        }
        $encrypted = '';
        if (openssl_public_encrypt($str, $encrypted, $content, OPENSSL_PKCS1_OAEP_PADDING)) {
            //base64编码
            $sign = base64_encode($encrypted);
        }
        else {
            throw new \Exception('encrypt failed');
        }
        return $sign;
    }

    /**
     * 获取支付平台证书
     * @return false|string
     */
    public function getCertFicates()
    {
        $public_key_path = $this->public_key_path;
        if (!file_exists($public_key_path)) {
            $cfData = $this->certFicates();

            $content = $this->decryptToString($cfData['encrypt_certificate']['associated_data'], $cfData['encrypt_certificate']['nonce'], $cfData['encrypt_certificate']['ciphertext'], $this->mch_api_key);
            file_put_contents($public_key_path, $content);
        }
        else {
            $content = file_get_contents($public_key_path);
        }
        return $content;
    }

    /**
     * 业务编号
     * @return string
     */
    private function getBusinessCode()
    {
        return date('Ymd') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));
    }

    /**
     * 随机字符串
     * @param int $length
     * @return string
     */
    private function getNonceStr($length = 16)
    {
        // 密码字符集，可任意添加你需要的字符
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str   = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $str;
    }

    /**
     * @param string       $method
     * @param string       $url
     * @param array|string $data
     * @param array        $headers
     * @param int          $timeout
     * @return bool|string
     */
    private function getCurl($method = 'GET', $url, $data, $headers = [], $timeout = 10)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);

        if (!empty($headers)) {
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }
        if ($method == 'POST') {
            curl_setopt($curl, CURLOPT_POST, TRUE);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        else {
        }
        $result = curl_exec($curl);

        curl_close($curl);
        return $result;
    }

    /**
     * Decrypt AEAD_AES_256_GCM ciphertext(官方案例-已改造)
     *
     * @param string $associatedData AES GCM additional authentication data
     * @param string $nonceStr       AES GCM nonce
     * @param string $ciphertext     AES GCM cipher text
     *
     * @return string|bool      Decrypted string on success or FALSE on failure
     */
    private function decryptToString($associatedData, $nonceStr, $ciphertext, $aesKey)
    {
        $auth_tag_length_byte = 16;

        $ciphertext = \base64_decode($ciphertext);
        if (strlen($ciphertext) <= $auth_tag_length_byte) {
            return false;
        }

        // ext-sodium (default installed on >= PHP 7.2)
        if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') &&
            \sodium_crypto_aead_aes256gcm_is_available()) {
            return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey);
        }

        // ext-libsodium (need install libsodium-php 1.x via pecl)
        if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') &&
            \Sodium\crypto_aead_aes256gcm_is_available()) {
            return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey);
        }

        // openssl (PHP >= 7.1 support AEAD)
        if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
            $ctext   = substr($ciphertext, 0, -$auth_tag_length_byte);
            $authTag = substr($ciphertext, -$auth_tag_length_byte);

            return \openssl_decrypt($ctext, 'aes-256-gcm', $aesKey, \OPENSSL_RAW_DATA, $nonceStr,
                $authTag, $associatedData);
        }

        throw new \Exception('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
    }

    /**
     * 获取证书编号(官方案例-已改造)
     * @param $certificate
     * @return string
     */
    public function parseSerialNo($certificate)
    {
        $info = \openssl_x509_parse($certificate);
        if (!isset($info['serialNumber']) && !isset($info['serialNumberHex'])) {
            throw new \InvalidArgumentException('证书格式错误');
        }

        $serialNo = '';
        // PHP 7.0+ provides serialNumberHex field
        if (isset($info['serialNumberHex'])) {
            $serialNo = $info['serialNumberHex'];
        }
        else {
            // PHP use i2s_ASN1_INTEGER in openssl to convert serial number to string,
            // i2s_ASN1_INTEGER may produce decimal or hexadecimal format,
            // depending on the version of openssl and length of data.
            if (\strtolower(\substr($info['serialNumber'], 0, 2)) == '0x') { // HEX format
                $serialNo = \substr($info['serialNumber'], 2);
            }
            else { // DEC format
                $value     = $info['serialNumber'];
                $hexvalues = ['0', '1', '2', '3', '4', '5', '6', '7',
                    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
                while ($value != '0') {
                    $serialNo = $hexvalues[\bcmod($value, '16')] . $serialNo;
                    $value    = \bcdiv($value, '16', 0);
                }
            }
        }

        return \strtoupper($serialNo);
    }

    public function getError()
    {
        return $this->error;
    }

}
